package edu.kpi.pzks2.simulator.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.kpi.pzks2.graph.Edge;
import edu.kpi.pzks2.graph.Node;
import edu.kpi.pzks2.simulator.core.QueueBuilder;
import edu.kpi.pzks2.simulator.core.Simulator;
import edu.kpi.pzks2.simulator.core.strategy.Strategy;
import edu.kpi.pzks2.simulator.processing.Processor;
import edu.kpi.pzks2.simulator.processing.Task;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Pair;

public abstract class BaseStrategyImpl implements Strategy {

    protected Graph<Node, Edge> taskGraph;
    protected Graph<Node, Edge> procGraph;
    protected Simulator simulator;
    protected Map<Node, Processor> processedTasks;
    protected Map<Node, Processor> processingTasks;
    
    private List<Node> taskQueue;
    
    protected BaseStrategyImpl(
            final Graph<Node, Edge> taskGraph,
            final Graph<Node, Edge> procGraph, 
            final QueueBuilder queueBuilder,
            final Simulator simulator) {
        this.taskGraph = taskGraph;
        this.procGraph = procGraph;
        this.simulator = simulator;
        
        processedTasks = new HashMap<Node, Processor>();
        processingTasks = new HashMap<Node, Processor>();
        taskQueue = queueBuilder.buildQueue(taskGraph);
    }
    
    public void taskEnded(Processor proc, Task task) {
        processedTasks.put(task.getNode(), proc);
    }

    public boolean isFinished() {
        return !(taskGraph.getVertexCount() > processedTasks.size());
    }

    public abstract void makeStep();

    protected List<Node>getReadyNodes() {
        final List<Node>nodes = new ArrayList<Node>();
        for (Node node : taskQueue) {
            if (isNodeReady(node) 
                    && !processedTasks.keySet().contains(node) 
                    && !processingTasks.keySet().contains(node)) {
                nodes.add(node);
            }
        }
        return nodes;
    }
    
    protected boolean isNodeReady(Node node) {
        for (Node predessor :taskGraph.getPredecessors(node)) {
            if (!processedTasks.keySet().contains(predessor)) {
                return false;
            }
        }
        return true;
    }
    
    protected Edge getEdgeBetweenAandB(final Node a, final Node b) {
        final List<Edge> edges = new ArrayList<Edge>();
        edges.addAll(taskGraph.getEdges());
        
        for (Edge e : edges) {
            final Pair<Node> ends = taskGraph.getEndpoints(e);
            if ((ends.getFirst() == a && ends.getSecond() == b) 
                    || (ends.getFirst() == b && ends.getSecond() == a)) {
                return e;
            }
        }
        
        return null;
    }
}
